// 引入uni-map-common公共模块
const UniMap = require('uni-map-common');
const redis = uniCloud.redis()

const configCenter = require("uni-config-center");
const linli = require('linliUtils')
// 读取配置中心地图配置
var UniMapConfig = configCenter({
	pluginId: 'uni-map'
}).requireFile('config.js');

// 本地地图配置
var LocalMapConfig = {
	"default": "amap", // 默认使用的平台
	"key": {
		"amap": "2642eb892bac2acb0eeacc2dc524ff1b", // 高德地图key	
		//"qqmap": "", // 腾讯地图key
	}
}

const db = uniCloud.database();

const _ = db.command;
const $ = _.aggregate;

const opendbPoiDB = db.collection("opendb-poi");

class MyError extends Error {
	constructor(errMsg, errCode = -1) {
		super(errMsg);
		this.err = {
			errCode,
			errMsg
		}
	}
}

module.exports = {
	_before: function() {
		// 如果配置中心不存在地图配置，则使用本地地图配置
		if (!UniMapConfig) {
			UniMapConfig = LocalMapConfig;
		}
		let defaultProvider = UniMapConfig.default;
		let params = this.getParams();
		let {
			provider = defaultProvider,
				needOriginalResult = false
		} = params[0] || {};
		const key = UniMapConfig.key[provider] || LocalMapConfig.key[provider];
		if (!key) {
			throw {
				errCode: -1,
				errMsg: `请在uni-config-center/uni-map/config.js中或LocalMapConfig中配置地图供应商${provider}对应的key`
			};
		}
		// 初始化实例
		let uniMap = new UniMap({
			provider: provider, // 指定使用哪家地图供应商
			key: key,
			needOriginalResult
		});
		this.uniMap = uniMap;
		const jqlCacheConfig = configCenter({
			pluginId: 'uni-jql-cache-redis' // 对应配置文件名（无需加 .json）
		}).requireFile('', {
			type: 'json'
		}); // 读取根目录下的 json 文件

		console.log("读取到的JQL缓存配置：", jqlCacheConfig);
		const clientInfo = this.getClientInfo()
		const methodName = this.getMethodName()
		const secretType = clientInfo.secretType
		if (methodName === 'chooseLocation' && secretType !== 'both' && secretType !== 'request') {
			throw new Error('Unauthorized client')
		}


		// // 在这里可以做一些统一的前置处理，比如权限校验、参数校验等
		// let {
		//   payload, // payload参数为前端传递的参数，可以在前端调用uni.chooseLocation时传递
		// } = this.getParams()[0] || {};
		// if (!payload) {
		//   throw new MyError("payload参数不能为空", -1);
		// }
		// // 如果业务在uniCloud上，则直接在这里写判断逻辑即可
		// if (true) {
		// 	throw new MyError("权限不足", -1);
		// }

		// // 如果业务不在uniCloud上，可通过 uniCloud.request 调用自己的服务进行校验
		// const requestRes = await uniCloud.request({
		//   method: 'POST',
		//   url: '你自己的接口地址',
		//   data: payload,
		// });
		// // 约定errCode不为0代表校验失败，errMsg为失败原因
		// if (requestRes.data.errCode !== 0) {
		//   throw new MyError(requestRes.data.errMsg, requestRes.data.errCode);
		// }

	},
	_after: function(err, res) {
		if (err) {
			if (err.err) {
				return err.err;
			}
			if (err.errCode) {
				return err;
			}
			throw err; // 如果方法抛出错误，也直接抛出不处理
		}
		console.log("result", res.result);
		return res;
	},
	// 函数chooseLocation是给uni.chooseLocation使用，请勿修改chooseLocation函数的代码
	async chooseLocation(parame = {}) {
		let res = {};
		let {
			action,
			data,
			needOriginalResult
		} = parame;
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		let result = await uniMap[action](data);
		res.result = needOriginalResult ? result.originalResult : result;
		// 模拟错误
		// res.errCode = 121;
		// res.errMsg = '此key每日调用量已达到上限'
		return res;
	},
	// 经纬度坐标转地址
	async location2address(location) {
		try {
			const db = uniCloud.databaseForJQL();
			const grid = linli.getGridCode(location);
			console.log("当前grid：", grid);
			const redisCacheKey = `poiAddress:${grid}`; // 定义Redis缓存键

			// 1. 优先查询Redis缓存
			const redisCache = await redis.get(redisCacheKey);
			if (redisCache) {
				console.log("命中Redis缓存");
				const parsedCache = JSON.parse(redisCache);
				return parsedCache;
			}

			// 2. Redis未命中，查询数据库
			const queryResult = await db.collection('poiAddress').where({
				grid: grid
			}).get();
			const ress = queryResult.data || []; // 确保数组安全
            
			if (ress.length > 0) {
				const cachedData = ress[0];
				// 验证地址有效性
				if (cachedData.address && cachedData.address.length > 0) {
					const returnData = {
						address: cachedData.address,
						cityAddress:cachedData.cityAddress,
						addressShort: cachedData.addressShort || (cachedData.address.length > 16 ?
							`...${cachedData.address.slice(-16)}` : cachedData.address),
						grid: grid
					};

					// 写入Redis并设置过期时间（避免永久缓存）
					await redis.set(redisCacheKey, JSON.stringify(returnData), 'EX', 86400);
					console.log("数据库数据写入Redis缓存");
					return returnData;
				}
			}

			// 3. 无任何缓存，调用地图接口
			const uniMap = this.uniMap;
			const data = {
				location: `${location.latitude},${location.longitude}`,
				get_poi: 1,
				poi_options: {
					address_format: 'short',
					radius: 50,
					policy: 4,
					roadlevel: 1,
					homeorcorp: 1
				}
			};

			const apiResult = await uniMap.location2address(data);
			console.log('...........apiResult',apiResult);
			const address = apiResult.result?.formatted_addresses;
			if (!address) {
				throw new Error("地图接口未返回有效地址");
			}

			const addressShort = address.length > 16 ? `...${address.slice(-16)}` : address;
			const newAddress = {
				grid: grid,
				address: address,
				addressShort: addressShort,
				cityAddress:apiResult.result.province+apiResult.result.city+apiResult.result.district,
				createTime: Date.now()
			};

			// 4. 存储到数据库（先删后加避免重复）
			await db.collection('poiAddress').where({
				grid: grid
			}).remove();
			await db.collection('poiAddress').add(newAddress);

			// 5. 写入Redis并设置过期时间
			await redis.set(redisCacheKey, JSON.stringify(newAddress), 'EX', 3600);
			console.log("地图接口数据写入缓存");

			return newAddress;

		} catch (e) {
			console.error("location2address错误：", e);
			throw e; // 保持错误冒泡，让上层处理
		}
	},
   async loc2add(data){
	   return await this.uniMap.location2address(data)
   },
	// 地址转经纬度坐标
	async address2location(data = {}) {

		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		return await uniMap.address2location(data);

		
	},
	// 坐标系转换
	async translate(data = {}) {
		let res = {};
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		let result = await uniMap.translate(data);
		res.result = result;
		return res;
	},
	// ip定位
	async ip2location(data = {}) {
		let res = {};
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		let result = await uniMap.ip2location(data);
		res.result = result;
		return res;
	},
	// 输入提示
	async inputtips(data = {}) {
		let res = {};
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		let result = await uniMap.inputtips(data);
		res.result = result;
		return res;
	},

	// 搜索
	async search(data = {}) {
		let res = {};
		console.log("res.........", data)
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		let result = await uniMap.search(data);
		res.result = result;
		return res;
	},
	//自写搜索

	// 行政区划
	async districtSearch(data = {}) {
		let res = {};
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		let result = await uniMap.districtSearch(data);
		res.result = result;
		return res;
	},

	// 路径规划
	async route(data = {}) {
		let res = {};
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		let result = await uniMap.route(data);
		res.result = result;
		return res;
	},

	// 演示用 - 清空所有的测试POI
	async clearPoi(data = {}) {
		let res = {
			errCode: 0
		};
		const db = uniCloud.database();
		await db.collection("opendb-poi").where({
			is_random: true
		}).remove();
		return res;
	},
	async getNearbyGroup() {

		try {

			const groupInDB = await db.collection('Group').get()
			const list = [];
			const abj = {
				category: 'group', // 场景值，用于区分这些POI所属哪张地图
				type: "group",
				title: '',
				location: null,
				create_date: new Date(),
				visible: true,
				is_random: true, // 表示此为随机生成的点，方便删除
				level: 1
			};
			let level = 1;
			groupInDB.data.forEach((item) => {
				const newAbj = {
					...abj
				};
				newAbj.title = item.groupName;
				newAbj.location = item.polygons;
				newAbj.level = level++;
				newAbj.icon = item.groupPicPath
				list.push(newAbj);
			});
			await opendbPoiDB.add(list);

			// 处理查询结果
			const nearbyGroup = groupInDB.data;
			console.log('附近用户:', nearbyGroup);
			return nearbyGroup;
		} catch (error) {
			// 错误处理
			console.error('查询附近用户时出错:', error);
			return [];
		}
	},
	//初始化用户所在位置
	async getNearbyUsers(user = {}) {

		try {
			const db = uniCloud.database(); // 假设 db 是这样获取的
			const userInDB = await db.collection('opendb-poi')
				.get()
			const list = [];
			const abj = {
				category: 'user', // 场景值，用于区分这些POI所属哪张地图
				type: "user",
				title: '',
				icon: "",
				location: null,
				create_date: new Date(),
				visible: true,
				is_random: true, // 表示此为随机生成的点，方便删除
				level: 1
			};
			let level = 1;
			userInDB.data.forEach((item) => {
				const newAbj = {
					...abj
				};
				newAbj.title = item.userInDB;
				newAbj.location = item.location;
				newAbj.level = level++;
				newAbj.icon = item.nicPic
				list.push(newAbj);

			});
			await opendbPoiDB.add(list);

			// 处理查询结果
			const nearbyUsers = userInDB.data;
			console.log('附近用户:', nearbyUsers);
			return nearbyUsers;
		} catch (error) {
			// 错误处理
			console.error('查询附近用户时出错:', error);
			return [];
		}
	},
	// 演示用 - 初始化静态001场景演示数据
	async initStatic001(data = {}) {
		let res = {
			errCode: 0
		};
		const category = "static-001";
		// 先删除
		await opendbPoiDB.where({
			category: category
		}).remove();
		// 后添加随机数据

		// 以天安门为中心
		let tiananmen = {
			longitude: 116.39747,
			latitude: 39.908823,
		};
		let time = Date.now();

		// 随机生成6个门店地址
		let list = [];
		for (let i = 1; i <= 60; i++) {
			let randomCoordinate = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude,
			10); // 随机生成在天安门方圆X KM内的坐标
			list.push({
				category: category, // 场景值，用于区分这些POI所属哪张地图
				type: "门店",
				title: `随机门店-${i}`,
				location: new db.Geo.Point(randomCoordinate.longitude, randomCoordinate.latitude),
				create_date: time,
				visible: true,
				is_random: true, // 表示此为随机生成的点，方便删除
				level: i
			});
		}
		// 随机生成1个总部地址
		let randomCoordinate = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude,
		1); // 随机生成在天安门方圆X KM内的坐标
		list.push({
			category: category, // 场景值，用于区分这些POI所属哪张地图
			type: "总部",
			title: `随机总部`,
			location: new db.Geo.Point(randomCoordinate.longitude, randomCoordinate.latitude),
			create_date: time,
			visible: true,
			is_random: true, // 表示此为随机生成的点，方便删除
			level: 7
		});

		// 添加到数据库
		await opendbPoiDB.add(list);

		return res;
	},

	// 演示用 - 初始化动态001场景演示数据（模拟送外卖场景）
	async initDynamics001(data = {}) {
		let res = {
			errCode: 0
		};

		const category = "dynamics-001";

		// 先删除
		await opendbPoiDB.where({
			category: category
		}).remove();
		// 后添加随机数据

		// 以天安门为中心
		let tiananmen = {
			longitude: 116.39747,
			latitude: 39.908823,
		};

		let time = Date.now();

		// 随机生成配送员坐标
		let randomCoordinate1 = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude,
		2); // 随机生成在天安门方圆X KM内的坐标
		let data1 = {
			category: category, // 场景值，用于区分这些POI所属哪张地图
			type: "配送员",
			title: "配送员",
			location: new db.Geo.Point(randomCoordinate1.longitude, randomCoordinate1.latitude),
			create_date: time,
			visible: true,
			is_random: true, // 表示此为随机生成的点，方便删除
			level: 0,
			width: 40,
			height: 40
		}
		// 随机生成目的地坐标
		let randomCoordinate2 = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude,
		2); // 随机生成在天安门方圆X KM内的坐标
		let data2 = {
			category: category, // 场景值，用于区分这些POI所属哪张地图
			type: "目的地",
			title: "配送目的地",
			location: new db.Geo.Point(randomCoordinate2.longitude, randomCoordinate2.latitude),
			create_date: time,
			visible: true,
			is_random: true, // 表示此为随机生成的点，方便删除
			level: 1,
			width: 30,
			height: 30
		}
		let list = [data1, data2];
		// 添加到数据库
		await opendbPoiDB.add(list);

		// 获取配送路线
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用电瓶车路径规划API
		let result = await uniMap.route({
			mode: "ebicycling",
			from: `${randomCoordinate1.latitude},${randomCoordinate1.longitude}`,
			to: `${randomCoordinate2.latitude},${randomCoordinate2.longitude}`,
			alternative_route: 1
		});

		let route = result.result.routes[0];
		let {
			steps = []
		} = route;
		let points = [];
		steps.map((step) => {
			let {
				polyline = ""
			} = step;
			let arr = polyline.split(";");
			arr.map((item) => {
				let arr2 = item.split(",");
				points.push({
					latitude: Number(arr2[0]),
					longitude: Number(arr2[1]),
				});
			});
		});
		let polyline = {
			points,
			color: "#19b411",
			width: 6,
			dottedLine: false,
			arrowLine: true,
			borderWidth: 1,
			borderColor: "#000000",
		};
		res.polyline = [polyline];
		return res;
	},

	// 演示用 - 获取配送员配送路径
	async getPolyline(data = {}) {
		let res = {
			errCode: 0
		};

		const category = "dynamics-001";

		let getRes1 = await opendbPoiDB.where({
			category: category,
			type: "配送员",
			visible: true
		}).get();
		let poi1 = getRes1.data[0];

		let getRes2 = await opendbPoiDB.where({
			category: category,
			type: "目的地",
			visible: true
		}).get();
		let poi2 = getRes2.data[0];
		if (!poi2) {
			return {
				errCode: 0,
				end: true
			}
		}

		let coordinate1 = {
			longitude: poi1.location.coordinates[0],
			latitude: poi1.location.coordinates[1]
		};

		let coordinate2 = {
			longitude: poi2.location.coordinates[0],
			latitude: poi2.location.coordinates[1]
		};

		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用电瓶车路径规划API
		let result = await uniMap.route({
			mode: "ebicycling",
			from: `${coordinate1.latitude},${coordinate1.longitude}`,
			to: `${coordinate2.latitude},${coordinate2.longitude}`,
			alternative_route: 1
		});

		let route = result.result.routes[0];
		//console.log('route: ', route)
		let {
			steps = [], distance, duration
		} = route;
		let points = [];
		let dir_desc;
		steps.map((step) => {
			let {
				polyline = ""
			} = step;
			if (!dir_desc) dir_desc = step.dir_desc;
			if (polyline) {
				let arr = polyline.split(";");
				arr.map((item) => {
					let arr2 = item.split(",");
					if (!isNaN(arr2[0]) && !isNaN(arr2[1])) {
						points.push({
							latitude: Number(arr2[0]),
							longitude: Number(arr2[1]),
						});
					}
				});
			}
		});
		let polyline = {
			points,
			color: "#19b411",
			width: 6,
			dottedLine: false,
			arrowLine: true,
			borderWidth: 1,
			borderColor: "#000000",
		};
		res.polyline = [polyline];
		if (distance <= 30 || duration <= 0) {
			await opendbPoiDB.doc(poi1._id).update({
				title: `配送员已到达目的地`,
				location: new db.Geo.Point(Number(coordinate2.longitude), Number(coordinate2.latitude)),
				rotate: 0
			});
			// 隐藏目的地
			await opendbPoiDB.doc(poi2._id).update({
				visible: false,
			});
			return {
				errCode: 0,
				end: true
			}
		} else {
			// 从最近2个点计算出当前行驶方向
			// let rotate = 0;
			// if (points && points.length >= 2) {
			// 	rotate = calculateDirectionAngle(points[0], points[1]);
			// }
			// await opendbPoiDB.doc(poi1._id).update({
			// 	title: `配送员正在配送\r\n还有 ${distance} 米\r\n预计 ${duration} 分钟送达`,
			// 	rotate: rotate, // 设置角度，0°的图片方向应朝左(西) 故90° 朝上(北) 180° 朝右(东) 270° 朝下(南)
			// });
			await opendbPoiDB.doc(poi1._id).update({
				title: `配送员正在配送\r\n还有 ${distance} 米\r\n预计 ${duration} 分钟送达`,
				rotate: 0,
			});
		}
		return res;
	},
	// 演示用 - 模拟上报配送员坐标
	async updateMyLocation(data = {}) {
		let res = {};

		const category = "dynamics-001";

		let {
			longitude,
			latitude
		} = data;

		let getRes1 = await opendbPoiDB.where({
			category: category,
			type: "配送员",
			visible: true
		}).get();
		let poi1 = getRes1.data[0];

		await opendbPoiDB.doc(poi1._id).update({
			location: new db.Geo.Point(Number(longitude), Number(latitude))
		});
		return res;
	},

	// 演示用 - xxxx
	async test(data = {}) {
		let res = {};
		// 获取uniMap实例
		const uniMap = this.uniMap;
		// 调用API
		let result = await uniMap.location2address({

		});
		res.result = result;
		return res;
	}
}



/**
 * 生成在指定经纬度圆内的随机坐标
 
const latitude = 39.908823; // 指定纬度
const longitude = 116.39747; // 指定经度
const radiusInKm = 10; // 指定圆的半径（单位：千米）

const randomCoordinate = getRandomCoordinateWithinRadius(latitude, longitude, radiusInKm);
console.log(randomCoordinate);

 */
function getRandomCoordinateWithinRadius(longitude, latitude, radiusInKm) {
	// 地球半径（单位：千米）
	const earthRadius = 6371;

	// 将圆的半径转换为弧度
	const radiusInRad = radiusInKm / earthRadius;

	// 生成随机的方位角（弧度，0到2π）
	const randomAngleRad = Math.random() * 2 * Math.PI;

	// 生成随机的距离（弧度，0到圆的半径）
	const randomDistanceRad = Math.acos(Math.random() * (Math.cos(radiusInRad) - 1) + 1);

	// 使用球面三角学计算随机点的纬度和经度
	const randomLatitudeRad = latitude * (Math.PI / 180) + randomDistanceRad * Math.cos(randomAngleRad);
	const randomLongitudeRad = longitude * (Math.PI / 180) + randomDistanceRad * Math.sin(randomAngleRad) / Math.cos(
		latitude * (Math.PI / 180));

	// 转换为度，并保留6位小数
	const randomLatitude = parseFloat((randomLatitudeRad * (180 / Math.PI)).toFixed(6));
	const randomLongitude = parseFloat((randomLongitudeRad * (180 / Math.PI)).toFixed(6));

	return {
		latitude: randomLatitude,
		longitude: randomLongitude
	};
}


/**
 * 计算坐标B在坐标A的方向，0代表正西方 90 代表正北方
 
const latitude = 39.908823; // 指定纬度
const longitude = 116.39747; // 指定经度
const radiusInKm = 10; // 指定圆的半径（单位：千米）

const randomCoordinate = getRandomCoordinateWithinRadius(latitude, longitude, radiusInKm);
console.log(randomCoordinate);

 */
function calculateDirectionAngle(coordA, coordB) {
	const toRadians = (angle) => angle * (Math.PI / 180);
	const toDegrees = (angle) => angle * (180 / Math.PI);

	const lat1 = toRadians(coordA.latitude);
	const lon1 = toRadians(coordA.longitude);
	const lat2 = toRadians(coordB.latitude);
	const lon2 = toRadians(coordB.longitude);

	const dLon = lon2 - lon1;
	const y = Math.sin(dLon) * Math.cos(lat2);
	const x =
		Math.cos(lat1) * Math.sin(lat2) -
		Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
	const angleRadians = Math.atan2(y, x);

	let angleDegrees = toDegrees(angleRadians);
	angleDegrees = (angleDegrees + 360) % 360;

	angleDegrees = (angleDegrees > 180) ? angleDegrees - 180 : angleDegrees + 180;
	angleDegrees -= 90; // 以正西方为0°表示，因此需要-90
	return angleDegrees;
}